package com.sharer.last.config;

import com.sharer.last.handler.SecurityAuthenticationFailureHandler;
import com.sharer.last.handler.SecurityAuthenticationSuccessHandler;
import com.sharer.last.service.impl.UserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.Authentication;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.client.DefaultOAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.AccessTokenRequest;
import org.springframework.security.oauth2.client.token.DefaultAccessTokenRequest;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeAccessTokenProvider;
import org.springframework.security.oauth2.client.token.grant.password.ResourceOwnerPasswordResourceDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * 认证服务器配置
 *
 * @ClassName SecurityConfig
 * @Author WangJin
 * @Date 2023/05/09/14:14
 * @Description Oauth2依赖于Security 默认情况下SecurityConfig执行比ResourceServerConfig优先
 * @Version 1.0
 */
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource
    private SecurityAuthenticationSuccessHandler securityAuthenticationSuccessHandler;

    @Resource
    private SecurityAuthenticationFailureHandler securityAuthenticationFailureHandler;

    @Resource
    UserServiceImpl userService;

    @Resource
    private DataSource dataSource;//注入数据源


    @Bean//Token持久化存储
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();//这个接口完成建表，查询，修改等操作
        //public static final String CREATE_TABLE_SQL = "create table persistent_logins (username varchar(64) not null, series varchar(64) primary key, "
        //			+ "token varchar(64) not null, last_used timestamp not null)";
        tokenRepository.setDataSource(dataSource);
        tokenRepository.setCreateTableOnStartup(false);//启动的时候会自动建表--但是这里没有表已存在不建表的操作，所以表存在后不能再次开启
        return tokenRepository;

    }

//    @Bean
//    public OAuth2RestTemplate oauth2RestTemplate( OAuth2ProtectedResourceDetails details) {
//        OAuth2RestTemplate template = new OAuth2RestTemplate(details);
//        template.setAccessTokenProvider(new AuthorizationCodeAccessTokenProvider());
//        return template;
//    }
//
//    @Bean
//    protected OAuth2ProtectedResourceDetails resource() {
//        ResourceOwnerPasswordResourceDetails resource;
//        resource = new ResourceOwnerPasswordResourceDetails();
//
//        List scopes = new ArrayList<String>(2);
//        scopes.add("write");
//        scopes.add("read");
//        resource.setAccessTokenUri("http://localhost:8090/oauth/token");
//        resource.setClientId("client");
//        resource.setClientSecret("123456");
//        resource.setGrantType("password");
//        resource.setScope(scopes);
//        resource.setUsername("admin");
//        resource.setPassword("123456");
//        return resource;
//    }

//    /**
//     * 注册处理redirect uri的filter
//     * @param oauth2RestTemplate
//     * @param tokenService
//     * @return
//     */
//    @Bean
//    public OAuth2ClientAuthenticationProcessingFilter oauth2ClientAuthenticationProcessingFilter(
//            OAuth2RestTemplate oauth2RestTemplate)
//    {
//        OAuth2ClientAuthenticationProcessingFilter filter = new OAuth2ClientAuthenticationProcessingFilter("http://127.0.0.1:8090/");
//        filter.setRestTemplate(oauth2RestTemplate);
//        //设置回调成功的页面
//        filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler() {
//            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
//                this.setDefaultTargetUrl("/index");
//                super.onAuthenticationSuccess(request, response, authentication);
//            }
//        });
//        return filter;
//    }

    /**
     * 配置拦截器
     * @param http
     * @throws Exception
     */
    /**
     * 在Spring Security配置和资源服务器配置中，一共涉及两个HttpSecurity，
     * 其中Spring Security中的配置优先级高于资源服务器中的配置，
     * 即请求地址先经过Spring Security的HttpSecurity，再经过资源服务器的HttpSecurity。
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .formLogin()
                .usernameParameter("username").passwordParameter("password")
                .loginProcessingUrl("/login")//替换默认的login登录路径校验，
                .successHandler(securityAuthenticationSuccessHandler)//身份验证成功后调用实现类
                .failureHandler(securityAuthenticationFailureHandler)//身份验证失败后调用实现类
                .permitAll()
                .and().authorizeRequests()
                //指定了/和/inner_api/admin/login不需要任何认证就可以访问
                .antMatchers( "/login").permitAll()
                // 任何请求，登录后方可访问
                .anyRequest().authenticated()
                //登陆界面参数
                .and()
                .csrf().disable()
                .cors()
        ;//关闭SpringSecurity默认的跨站请求伪造防护
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 密码模式
     *
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager();
    }

//    /**
//     * 会自带继承父类的一些方法
//     *
//     * @param web
//     * @throws Exception
//     */
//    @Override
//    public void configure(WebSecurity web) throws Exception {
////  这个会在上面的过滤器执行之前执行
//        web.ignoring().antMatchers("/inner_api/admin/dashboard/index");
//    }

    /**
     * 配置user-detail 服务，就是定义用户的地方
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
    }

    public static void main(String[] args) {
        BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
        String                password              = bCryptPasswordEncoder.encode("123456");
        System.out.println(password);
    }
}
